package face.pay.web.advert.service.impl;


import com.alibaba.fastjson.JSON;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyun.oss.sdk.OSSUtils;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.push.model.v20160801.PushRequest;
import com.aliyuncs.push.model.v20160801.PushResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import face.pay.config.AliMobilePushConfig;
import face.pay.dao.*;
import face.pay.entity.*;
import face.pay.param.advert.MobilePushBatch;
import face.pay.param.advert.MobilePushParam;
import face.pay.util.ListSplitUtil;
import face.pay.util.ResultMessage;
import face.pay.util.page.PageData;
import face.pay.util.page.PageParam;
import face.pay.web.advert.service.IAdvertService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AdvertServiceImpl implements IAdvertService {


    @Autowired
    private AliMobilePushConfig aliMobilePushConfig;


    @Autowired
    private OemConfigInfoDao oemConfigInfoDao;


    @Autowired
    private FileInfoDao fileInfoDao;


    @Autowired
    private AdvertMaterialDao advertMaterialDao;


    @Autowired
    private TerminalInfoDao terminalInfoDao;

    @Autowired
    private AdvertBatchDao advertBatchDao;


    @Autowired
    private AdvertBatchMaterialDao advertBatchMaterialDao;

    /**
     * 广告上传
     *
     * @param fileBytes
     * @param originalFilename
     * @param loginUser
     * @param ad_type
     * @param ad_title
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage fielUpload(byte[] fileBytes, String originalFilename, UserInfo loginUser, String ad_type, String ad_title) {

        if (isImage(originalFilename)) {
            ad_type = "image";
        } else if (isvideo(originalFilename)) {
            ad_type = "video";
        } else {
            return ResultMessage.createFail("只能上传图片或者视频");
        }

        //获取oem商的oss配置信息
        log.info("上传开始oemid{} 文件{}", loginUser.getOemId(), originalFilename);
        OemConfigInfo oemConfig = this.oemConfigInfoDao.getByOemId(loginUser.getOemId());
        if (oemConfig == null) {
            return ResultMessage.createFail();
        }
        //生成fielInfo和fullname
        FileInfo fileInfo = new FileInfo(oemConfig.getOemId(), loginUser.getId(), originalFilename, "");
        String fullName = fileInfo.createAdvertFullName(oemConfig.getOemId());
        //推送到oss
        PutObjectResult putObjectResult = OSSUtils.putOSS(oemConfig.getEndPoint(), oemConfig.getAccessKeyId(), oemConfig.getAccessKeySecret(), oemConfig.getBucket(), fileInfo.getFullName(), fileBytes, true);
        if (null == putObjectResult) {
            log.error("上传失败oemid{} 文件{}", loginUser.getOemId(), originalFilename);
            return ResultMessage.createFail();
        }
        fileInfo.setCreatedBy(loginUser.getId());
        fileInfo.setUpdatedBy(loginUser.getId());
        this.fileInfoDao.insert(fileInfo);
        String url = "http://" + oemConfig.getBucket() + "." + oemConfig.getEndPoint() + "/" + fullName;
        AdvertMaterial ad = new AdvertMaterial();
        ad.setOemId(loginUser.getOemId());
        ad.setAd_title(ad_title);
        ad.setAd_type(ad_type);
        ad.setAd_name(originalFilename);
        ad.setUrl(url);
        ad.setFile_id(fileInfo.getId());
        ad.setCreatedBy(loginUser.getId());
        ad.setUpdatedBy(loginUser.getId());
        advertMaterialDao.insert(ad);
        log.info("上传成功oemid{} 文件{}", loginUser.getOemId(), originalFilename);
        return ResultMessage.createSuccess(ad);
    }


    /**
     * 判断是否是图片
     */
    private boolean isImage(String fileName) {
        //设置允许上传文件类型
        String suffixList = "jpg,gif,png,ico,bmp,jpeg";
        // 获取文件后缀
        String suffix = fileName.substring(fileName.lastIndexOf(".")
                + 1, fileName.length());
        if (suffixList.contains(suffix.trim().toLowerCase())) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否是视频
     */
    private boolean isvideo(String fileName) {
        //设置允许上传文件类型
        String suffixList = "avi,flv,mpg,mpeg,mpe,m1v,m2v,mpv2,mp2v,dat,ts,tp,tpr,pva,pss,mp4,m4v,m4p,m4b,3gp,3gpp,3g2,3gp2,ogg,mov,qt,amr,rm,ram,rmvb,rpm";
        // 获取文件后缀
        String suffix = fileName.substring(fileName.lastIndexOf(".")
                + 1, fileName.length());
        if (suffixList.contains(suffix.trim().toLowerCase())) {
            return true;
        }
        return false;
    }


    /**
     * 查询广告列表
     *
     * @param pageParam
     * @param loginUser
     * @param advertMaterial
     * @return
     */
    @Override
    public PageData queryAdList(PageParam pageParam, UserInfo loginUser, AdvertMaterial advertMaterial) {
        PageHelper.startPage(pageParam.getPageNo(), pageParam.getPageSize());
        advertMaterial.setOemId(loginUser.getOemId());
        List<AdvertMaterial> list = this.advertMaterialDao.queryAdvertMaterial(advertMaterial);
        PageInfo<AdvertMaterial> pageInfo = new PageInfo<AdvertMaterial>(list);
        PageData<AdvertMaterial> pageData = new PageData<AdvertMaterial>(pageInfo.getTotal(), list);
        return pageData;
    }


    /**
     * 查询设备列表
     *
     * @param pageParam
     * @param loginUser
     * @return
     */
    @Override
    public PageData queryTerminalList(PageParam pageParam, UserInfo loginUser) {
        PageHelper.startPage(pageParam.getPageNo(), pageParam.getPageSize());
        TerminalInfo record = new TerminalInfo();
        record.setOemId(loginUser.getOemId());
        record.setType("WECHAT");
        List<TerminalInfo> list = this.terminalInfoDao.queryDetailList(record);
        PageInfo<TerminalInfo> pageInfo = new PageInfo<TerminalInfo>(list);
        PageData<TerminalInfo> pageData = new PageData<TerminalInfo>(pageInfo.getTotal(), list);
        return pageData;
    }


    /**
     * 新增一个广告批次
     *
     * @param loginUser
     * @param advertBatch
     * @param terList
     * @param adList
     * @return
     */
    @Override
    public ResultMessage insertAdvertBatch(UserInfo loginUser, AdvertBatch advertBatch) {
        advertBatch.setOemId(loginUser.getOemId());
        advertBatch.setStatus(0);
        advertBatch.setCreatedBy(loginUser.getId());
        advertBatch.setUpdatedBy(loginUser.getId());
        this.advertBatchDao.insert(advertBatch);
        return ResultMessage.createSuccess();
    }


    /**
     * 配置广告
     *
     * @param loginUser
     * @param advertBatch
     * @param adList
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultMessage updatAdvert(UserInfo loginUser, AdvertBatch advertBatch, String adList) {
        //插入广告和批次中间表
        AdvertBatchMaterial advertBatchMaterial = new AdvertBatchMaterial();
        advertBatchMaterial.setOemId(loginUser.getOemId());
        advertBatchMaterial.setBatch_id(advertBatch.getId());
        advertBatchMaterial.setCreatedBy(loginUser.getId());
        advertBatchMaterial.setUpdatedBy(loginUser.getId());
        if(StringUtils.isBlank(adList)){
            return ResultMessage.createFail("至少选择一个广告!!!");
        }
        List<String> str_list = Arrays.asList(adList.split(","));
        if (str_list.isEmpty()) {
            return ResultMessage.createFail("至少选择一个广告!!!");
        }
        List<Integer> list = str_list.stream().map(s -> {
            return Integer.parseInt(s);
        }).collect(Collectors.toList());
        for (Integer ad : list) {
            advertBatchMaterial.setMaterial_id(ad);
            this.advertBatchMaterialDao.insert(advertBatchMaterial);
        }
        advertBatch.setStatus(1);
        this.advertBatchDao.update(advertBatch);
        return ResultMessage.createSuccess();
    }

    /**
     * 配置设备
     *
     * @param loginUser
     * @param advertBatch
     * @param terList
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultMessage updatTerminal(UserInfo loginUser, AdvertBatch advertBatch, String terList) {
        if (advertBatch.getAllPush().equals(1)) {
            //全部推送
            TerminalInfo record = new TerminalInfo();
            record.setOemId(loginUser.getOemId());
            record.setType("WECHAT");
            List<TerminalInfo> list = this.terminalInfoDao.queryDetailList(record);
            List<Integer> allList = list.stream().map(info -> {
                return info.getId();
            }).collect(Collectors.toList());
            advertBatch.setTerminal_list(StringUtils.join(allList.toArray(), ","));
            advertBatch.setCount(allList.size());
            this.advertBatchDao.update(advertBatch);
        } else {
            //部分推送
            if (StringUtils.isBlank(terList)) {
                return ResultMessage.createFail("至少选择一个设备!!!");
            }
            List<String> list = Arrays.asList(terList.split(","));
            if (list.isEmpty()) {
                return ResultMessage.createFail("至少选择一个设备!!!");
            }
            advertBatch.setTerminal_list(terList);
            advertBatch.setCount(list.size());
            this.advertBatchDao.update(advertBatch);
        }
        advertBatch.setStatus(2);
        this.advertBatchDao.update(advertBatch);
        return ResultMessage.createSuccess();
    }

    /**
     * 分页查询当前oem商下的广告批次
     *
     * @param pageParam
     * @param loginUser
     * @param advertBatch
     * @return
     */
    @Override
    public PageData queryAdvertBatchlList(PageParam pageParam, UserInfo loginUser, AdvertBatch advertBatch) {
        PageHelper.startPage(pageParam.getPageNo(), pageParam.getPageSize());
        advertBatch.setOemId(loginUser.getOemId());
        List<AdvertBatch> list = this.advertBatchDao.queryAdvertBatch(advertBatch);
        PageInfo<AdvertBatch> pageInfo = new PageInfo<>(list);
        PageData<AdvertBatch> pageData = new PageData<>(pageInfo.getTotal(), list);
        return pageData;
    }


    /**
     * 查询广告详情
     *
     * @param loginUser
     * @param batchId
     * @return
     */
    @Override
    public ResultMessage queryBatchlinfo(UserInfo loginUser, Integer batchId) {
        List<AdvertMaterial> list = this.advertMaterialDao.queryAdvertinfo(batchId);
        return ResultMessage.createSuccess(list);
    }

    /**
     * 广告推送
     *
     * @param loginUser
     * @param advertBatch
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultMessage adPush(UserInfo loginUser, Integer batchId) {
        AdvertBatch advertBatch = this.advertBatchDao.getById(batchId);

        //准备消息体
        MobilePushParam pushParam = new MobilePushParam();
        pushParam.setSendTime(System.currentTimeMillis());
        pushParam.setMessageType("advertiser");
        MobilePushBatch batchData = new MobilePushBatch();
        List<AdvertMaterial> adlist = this.advertMaterialDao.queryAdvertinfo(batchId);
        batchData.setBatchNo(batchId);
        batchData.setAdvertiseList(adlist);
        pushParam.setData(batchData);
        // 转换为json
        String PushBody = JSON.toJSONString(pushParam);


        //推送目标
        List<String> terList = Arrays.asList(advertBatch.getTerminal_list().split(","));
        List<TerminalInfo> ters = this.terminalInfoDao.getByIds(terList);
        //所有device
        List<String> devs = ters.stream().map(t -> {
            return t.getDeviceId();
        }).collect(Collectors.toList());

        //按一千个划分
        List<List<?>> batchs = ListSplitUtil.splitList(devs, 1000);

        log.info(">>>>>>>广告推送开始batchId:{} oemId:{} 推送内容{}", batchId, loginUser.getOemId(), PushBody);

        for (List<?> batch : batchs) {
            String devices = StringUtils.join(batch.toArray(), ",");
            Boolean pashResult = getPashResult(devices, PushBody);

            if (!pashResult) {
                advertBatch.setStatus(-1);
                this.advertBatchDao.update(advertBatch);
                log.error("推送失败!!!!!batchId:{} oemId{}", batchId, loginUser.getOemId());
                return ResultMessage.createFail("推送失败!!!");
            }
        }
        advertBatch.setStatus(3);
        this.advertBatchDao.update(advertBatch);
        log.info("<<<<<<<广告推送成功batchId:{} oemId{}", batchId, loginUser.getOemId());
        return ResultMessage.createSuccess();
    }


    private Boolean getPashResult(String devices, String pushBody) {
        DefaultProfile profile = DefaultProfile.getProfile(
                "cn-hangzhou",
                aliMobilePushConfig.getAccessKeyId(),      // The AccessKey ID of the RAM account
                aliMobilePushConfig.getAccessKeySecret()); // The AccessKey Secret of the RAM account

        IAcsClient client = new DefaultAcsClient(profile);

        PushRequest request = new PushRequest();

        //安全性比较高的内容建议使用HTTPS
        request.setProtocol(ProtocolType.HTTPS);
        //内容较大的请求，使用POST请求
        request.setMethod(MethodType.POST);

        request.setAppKey(aliMobilePushConfig.getAppKey()); //Your AppKey
        request.setPushType("MESSAGE");
        request.setDeviceType("ANDROID");
        request.setTarget("ACCOUNT");
        request.setTargetValue(devices);
        request.setTitle("advertiser");
        request.setBody(pushBody);

        // 推送控制
        request.setStoreOffline(true); // 离线消息是否保存,若保存, 在推送时候，用户即使不在线，下一次上线则会收到

        try {
            PushResponse response = client.getAcsResponse(request);
            log.info("推送成功RequestId:{} MessageId{}", response.getRequestId(), response.getMessageId());
            return true;
        } catch (Exception e) {
            log.error(e.toString());
            return false;
        }
    }
}
